package org.softmed.rest.server.defaults.generation;

import groovy.lang.Binding;
import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyShell;
import groovy.util.GroovyScriptEngine;
import java.io.File;
import java.util.List;
import org.softmed.filehandling.FileUtil;
import org.softmed.rest.generation.HandlerSuite;
import org.softmed.rest.generation.ModuleBuilderManager;
import org.softmed.rest.generation.RESTModuleBuilder;
import org.softmed.rest.generation.scafold.AppConfig;
import org.softmed.rest.generation.scafold.ModConfig;
import org.softmed.rest.generation.scafold.build.ApplicationProcessor;

import org.softmed.rest.generation.suites.HandlerSuiteManager;

import com.google.inject.Inject;

public class DefaultModuleBuilderReader implements  ApplicationProcessor {

	@Inject
	GroovyScriptEngine groovyScriptEngine;

	@Inject
	GroovyClassLoader groovyClassLoader;

	FileUtil util = new FileUtil();

	String suiteName = "name";
	String suiteVariable = "builder";
	String fileName = "builder.groovy";

	@Override
	public void process(List<AppConfig> apps) throws Throwable {
		ModuleBuilderManager.clear();
		for (AppConfig app : apps) {
			try {
				readBuilders(app);
			} catch (Throwable t) {
				t.printStackTrace();
			}
		}
		System.out.println("ModuleBuilders Read");

	}

	private void readBuilders(AppConfig app) throws Throwable {
		File root = new File(app.getPath());
		File[] files = root.listFiles();
		for (File file : files) {
			if (file.isFile() && file.getName().equals(fileName))
				readAppBuilder(file, app);
		}

		List<ModConfig> mods = app.getModules();
		for (ModConfig mod : mods) {
			readModuleBuilder(app, mod);
		}

	}

	private void readModuleBuilder(AppConfig app, ModConfig mod)
			throws Throwable {
		File root = new File(mod.getPath());
		File[] files = root.listFiles();
		for (File file : files) {
			if (file.isFile() && file.getName().equals(fileName))
				readModuleSuite(file, app, mod);
		}
	}

	private void readModuleSuite(File file, AppConfig app, ModConfig mod)
			throws Throwable {
		String script = util.readFromFile(file);

		List<Class> classes = mod.getClasses();
		String importSnippet = "import org.softmed.rest.generation.RESTModuleBuilder;\n";
		// for (Class type : classes) {
		// importSnippet += "import " + type.getCanonicalName() + ";\n";
		// }

		script = importSnippet + script;

		Binding binding = new Binding();
		GroovyShell shell = new GroovyShell(groovyClassLoader, binding);

		try {
			shell.evaluate(script);
		} catch (Throwable t) {
			System.err.println("Error evaluating script " + file.getName()
					+ " from Module " + mod.getName() + " from Application "
					+ app.getName());
			System.err.println("Groovy Script File Path : "
					+ file.getCanonicalPath());
			t.printStackTrace();
		}

		String name = null;
		RESTModuleBuilder builder = null;
		try {
			name = (String) binding.getVariable(suiteName);
		} catch (Throwable t) {
			// t.printStackTrace();
		}

		try {
			builder = (RESTModuleBuilder) binding.getVariable(suiteVariable);

		} catch (Throwable t) {
			t.printStackTrace();
		}

		if (builder != null)
			ModuleBuilderManager.register(name, builder);

		mod.setModuleBuilder(name);
		// groovyScriptEngine.run(scriptName, binding);

	}

	private void readAppBuilder(File file, AppConfig app) throws Throwable {
		String script = util.readFromFile(file);

		List<Class> classes = app.getClasses();
		String importSnippet = "import org.softmed.rest.generation.RESTModuleBuilder;\n";
		// for (Class type : classes) {
		// importSnippet += "import " + type.getCanonicalName() + ";\n";
		// }

		script = importSnippet + script;

		Binding binding = new Binding();
		GroovyShell shell = new GroovyShell(groovyClassLoader, binding);

		try {
			shell.evaluate(script);
		} catch (Throwable t) {
			System.err.println("Error evaluating script " + file.getName()
					+ " from Application " + app.getName());
			System.err.println("Groovy Script File Path : "
					+ file.getCanonicalPath());
			throw t;
		}

		String name = null;
		RESTModuleBuilder builder = null;
		try {
			name = (String) binding.getVariable(suiteName);
		} catch (Throwable t) {
			// t.printStackTrace();
		}

		try {
			builder = (RESTModuleBuilder) binding.getVariable(suiteVariable);

		} catch (Throwable t) {
			// t.printStackTrace();
		}

		if (builder != null)
			ModuleBuilderManager.register(name, builder);

		app.setModuleBuilder(name);
	}

}
